/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package cy.jsonview.code;

import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author CangYan
 */
public class Kit {
    public final static String split = " : ";

    public final static String sign = "-";

    public final static String cNull = "k";
    public final static String cNum = "n";
    public final static String cObj = "o";
    public final static String cArr = "a";
    public final static String cStr = "v";
    public final static String cBool = "b";

    public final static String sNull = cNull + sign;
    public final static String sNum = cNum + sign;
    public final static String sObj = cObj + sign;
    public final static String sArr = cArr + sign;
    public final static String sStr = cStr + sign;
    public final static String sBool = cBool + sign;

    public final static String array = "Array";
    public final static String object = "Object";
    public static String baseResPath = "cy/jsonview/resources/";
    public static String QUOT = "\"";

    public static DefaultMutableTreeNode nullNode(String key) {
        return treeNode(sNull + key + split + "<null>");
    }

    public static DefaultMutableTreeNode nullNode(int index) {
        return nullNode(fkey(index));
    }

    public static DefaultMutableTreeNode numNode(String key, String val) {
        return treeNode(sNum + key + split + val);
    }

    public static DefaultMutableTreeNode numNode(int index, String val) {
        return numNode(fkey(index), val);
    }

    public static DefaultMutableTreeNode boolNode(String key, Boolean val) {
        String sVal = "false";
        if (val) {
            sVal = "true";
        }
        return treeNode(sBool + key + split + sVal);
    }

    public static DefaultMutableTreeNode boolNode(int index, Boolean val) {
        return boolNode(fkey(index), val);
    }

    public static DefaultMutableTreeNode strNode(String key, String val) {
        return treeNode(sStr + key + split + "\"" + val + "\"");
    }

    public static DefaultMutableTreeNode strNode(int index, String val) {
        return strNode(fkey(index), val);
    }

    public static DefaultMutableTreeNode objNode(String key) {
        return treeNode(sObj + key);
    }

    public static DefaultMutableTreeNode objNode(int index) {
        return objNode(fkey(index));
    }

    public static DefaultMutableTreeNode arrNode(String key) {
        return treeNode(sArr + key);
    }

    public static DefaultMutableTreeNode arrNode(int index) {
        return arrNode(fkey(index));
    }


    public static DefaultMutableTreeNode treeNode(String str) {
        return new DefaultMutableTreeNode(str);
    }

    public static DefaultMutableTreeNode treeNode(String type, int index, String val) {
        return treeNode(type + "[" + index + "]");
    }

    public static String fkey(int index) {
        return "[" + index + "]";
    }

    //"a-[" + i + "]"
    public static String fArrKey(int index) {
        return sArr + fkey(index);
    }


    public static int getIndex(String str) {
        int index = -1;
        if (str == null || str.length() == 0) {
            return index;
        }
        index = str.lastIndexOf("[");
        if (index >= 0) {
            try {
                index = Integer.parseInt(str.substring(index + 1, str.length() - 1));
            } catch (Exception ex) {
                index = -1;
            }
        }
        return index;
    }

    public static String getKey(String str) {
        int index = -1;
        if (str == null || str.length() == 0) {
            return str;
        }
        index = str.lastIndexOf("[");
        if (index >= 0) {
            return str.substring(0, index);
        }
        StringBuffer sb = null;
        return str;

    }

    public static String[] pstr(String str) {
        String[] arr = new String[3];//类型,key,value
        arr[0] = str.substring(0, 1);
        int i = str.indexOf(Kit.split);
//        if(i<0) return arr;
        if (Kit.cArr.equals(arr[0])) {
            arr[1] = str.substring(2);
            arr[2] = Kit.array;
        } else if (Kit.cObj.equals(arr[0])) {
            arr[1] = str.substring(2);
            arr[2] = Kit.object;
        } else if (Kit.cStr.equals(arr[0])) {
            arr[1] = str.substring(2, i);
            arr[2] = str.substring(i + 4, str.length() - 1);
        } else {
            arr[1] = str.substring(2, i);
            arr[2] = str.substring(i + 3, str.length());
        }
        return arr;
    }

    public static Map xmlToMap(String xml) throws SAXException, IOException, ParserConfigurationException {
        DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
        docBuilderFactory.setNamespaceAware(true);
        Document doc = docBuilderFactory.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
        Map rootMap = new HashMap();
        Map nodeMap = new HashMap();
        Node node = doc.getDocumentElement();
        xmlConversion(node, nodeMap);
        rootMap.put(node.getLocalName(), nodeMap);
        return rootMap;
    }

    private static void xmlConversion(Node node, Map nodeMap) {
        if (node.hasChildNodes()) {
            //Map nodeMap = new HashMap();
            NodeList childList = node.getChildNodes();
            for (int i = 0; i < childList.getLength(); i++) {
                Node childNode = childList.item(i);
                if (childNode.hasChildNodes()) {
                    int len = childNode.getChildNodes().getLength();
                    short nodeType = childNode.getFirstChild().getNodeType();
                    if (len == 1 && nodeType == Node.TEXT_NODE) {
                        String keyName = childNode.getLocalName();
                        String value = childNode.getFirstChild().getNodeValue();
                        if (null == nodeMap) {
                            nodeMap = new HashMap();
                        }
                        if (nodeMap.get(keyName) == null) {
                            nodeMap.put(keyName, value);
                        } else {
                            //if (null != value) {
                            List list = new ArrayList();
                            if (nodeMap.get(keyName) instanceof List) {
                                list = (List) nodeMap.get(keyName);
                            } else {
                                list.add(nodeMap.get(keyName));
                            }
                            list.add(value);
                            nodeMap.put(keyName, list);
                            //}
                        }
                    } else {
                        HashMap map = new HashMap();
                        xmlConversion(childNode, map);
                        // String keyName = childNode.getNodeName();
                        String keyName = childNode.getLocalName();

                        if (null == nodeMap) {
                            nodeMap = new HashMap();
                        }
                        if (null == nodeMap.get(keyName)) {
                            nodeMap.put(keyName, map);
                        } else {
                            List list = new ArrayList();
                            if (nodeMap.get(keyName) instanceof List) {
                                list = (List) nodeMap.get(keyName);
                            } else {
                                list.add(nodeMap.get(keyName));
                            }
                            list.add(map);
                            nodeMap.put(keyName, list);
                        }
                        if (childNode.getAttributes().getLength() > 0) {
                            String tmpName = childNode.getAttributes().item(0).getNodeName();
                            String tmpValue = childNode.getAttributes().item(0).getNodeValue();
                            nodeMap.put(tmpName, tmpValue);
                        }
                    }
                } else if (childNode.getNodeType() == Node.ELEMENT_NODE) {
                    if (StrUtil.isNotBlank(childNode.getLocalName())) {
                        nodeMap.put(childNode.getLocalName(), null);
                    }
                }
            }
            //rootMap.put(node.getLocalName(), nodeMap);
        }

    }

    public static String mapStringToJsonString(String mapstr) {
        mapstr = mapstr.replace(" ", "");
        mapstr = mapstr.replace("\"", "");
        mapstr = mapstr.replace("\r", "");
        mapstr = mapstr.replace("\n", "");
        mapstr = mapstr.replace("\t", "");
        int len = mapstr.length() - 1;
        StringBuilder json = new StringBuilder();
        for (int i = 0; i <= len; i++) {
            char c = mapstr.charAt(i);
            char cp = 0;
            if (i < len) {
                cp = mapstr.charAt(i + 1);
            }
            char cr = 0;
            if (i > 0) {
                cr = mapstr.charAt(i - 1);
            }

            //{[{aaa=
            if (c == '{' || c == '[') {
                if (cp == '}' || cp == ']') {
                    json.append(c).append(cp);
                    i++;
                    continue;
                }
                if (cp == '{' || cp == '[') {
                    json.append(c);
                    continue;
                }
                json.append(c).append(QUOT);
                continue;
            }
            //aa=aa ---> "aa":"aa"
            //aa={  ---> "aa":{
            //aa=[  ---> "aa":[
            //aa=,bb=bb ---> "aa":"","bb":"bb"
            if (c == '=') {
                if (cp == '{' || cp == '[') {
                    json.append(QUOT).append(":");
                    continue;
                }
                if (cp == ',') {
                    json.append(QUOT).append(":").append(QUOT).append(QUOT).append(cp);
                    i++;
                    continue;
                }
                json.append(QUOT).append(":").append(QUOT);
                continue;
            }

            // ],[     ],{   ],b 
            // },{     },[   },b
            // a,{     a,[   a,b     
            // aaa=,bb=ccc
            if (c == ',') {
                if (cr == '}' || cr == ']') {
                    if (cp == '{' || cp == '[') {
                        json.append(c);
                        continue;
                    }
                    json.append(c).append(QUOT);
                    continue;
                }
                if (cp == '{' || cp == '[') {
                    json.append(QUOT).append(c);
                    continue;
                }
                json.append(QUOT).append(c).append(QUOT);
                continue;
            }

            // a]}]},ad=sd
            if (c == '}' || c == ']') {
                if (cr == '}' || cr == ']') {
                    json.append(c);
                    continue;
                }
                json.append(QUOT).append(c);
                continue;
            }
            json.append(c);
        }
        return json.toString();
    }

    public static String formatXML(String xml, boolean isPrettyPrint) throws IOException {
        Document xmlDoc = XmlUtil.readXML(xml);
        final StringWriter writer = StrUtil.getWriter();
        String xmlStr = "";
        try {
            XmlUtil.write(xmlDoc, writer, CharsetUtil.UTF_8,
                    isPrettyPrint ? 4 : 0, false);
            writer.flush();
            xmlStr = writer.toString();
        } catch (Exception e) {
            throw new UtilException(e, "Trans xml document to string error!");
        } finally {
            writer.close();
        }
        return xmlStr;
    }
}
